package br.com.goldentrade.util.table;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

/**
 * 
 * @author Rafael
 * 
 * 		Classe responsavel pela cria��o de uma tabela e definir
 * 		a largura das colunas e o alinhamento do texto.
 *
 *		ex: new TableBase (modelCursos, new Integer[]{20, 150}, new Integer[]{SwingConstants.RIGHT, SwingConstants.LEFT});
 */
public class TableBase extends JTable
{

	private TableModelBase model;
	
	public TableBase() 
	{
		super();
		this.setRowHeight(22);
		
		this.setSelectionBackground(new Color(199,235,235));
		this.setSelectionForeground(Color.BLACK);
		/*@requisicao [2389]*/
		this.setRendererPadrao(new ColumnRenderer());
		
		new ExcelAdapter(this);
	}
	
	public TableBase(Integer sizes[]) 
	{
		super();
		setColumnSize(sizes);
		this.setRowHeight(22);
		
		this.setSelectionBackground(new Color(199,235,235));
		this.setSelectionForeground(Color.BLACK);
		/*@requisicao [2389]*/
		this.setRendererPadrao(new ColumnRenderer());
		
		new ExcelAdapter(this);
	}
	
	public void clearColumnModel(){
		this.setRowSorter(this.getRowSorter());
	}
	/**
	 * 
	 * @param model JTableModelBase defini o modelo da tabela.
	 * @param sizes Array contendo a medida da largura de cada coluna da tabela.
	 * @param aligns Array contendo o alinhamento de cada coluna da tabela.
	 */
	public TableBase (TableModelBase model, Integer sizes[], Integer aligns[], boolean addHeaderListener)
	{
		super();
		this.model = model;
		this.setModel(model);
		this.setColumnSize(sizes);
		this.setColumnAlign(aligns);
		
		this.setRowHeight(22);
		
		if (addHeaderListener)
			this.getTableHeader().addMouseListener(new HeaderListener (this.getTableHeader(), model));
		
		this.setSelectionBackground(new Color(199,235,235));
		this.setSelectionForeground(Color.BLACK);
		/*@requisicao [2389]*/
		this.setRendererPadrao(new ColumnRenderer());
		
		new ExcelAdapter(this);
	}
	
	public void addHeaderListener(){
		this.getTableHeader().addMouseListener(new HeaderListener (this.getTableHeader(), model));
	}
	
	public void removeHeaderListener(){
		MouseListener[] listeners = this.getTableHeader().getMouseListeners();
		if(listeners!=null && listeners.length>0){
			for (int i = 0; i < listeners.length; i++) {
				MouseListener headerListener = listeners[i];
				if(headerListener instanceof HeaderListener){
					this.getTableHeader().removeMouseListener(headerListener);
				}
				
			}
		}
	}
	
	/**
	 * 
	 * @param sizes array de medidas para largura das colunas da tabela.
	 * 
	 * Metodo responsavel por aplicar as larguras nas colunas da tabela.
	 */
	public void setColumnSize (Integer sizes[])
	{
		if (this.getColumnCount() > 0)
		{
			for (int i=0; i < this.getColumnCount(); i++)
			{
				if(sizes!=null && sizes.length>i){
					if(this.getColumnModel().getColumn(i)!=null)
						this.getColumnModel().getColumn(i).setPreferredWidth(sizes[i]);
				}
			}
		}
	}
	
	/**
	 * Recebe um array contendo os dados do alinhamento da coluna
	 * utiliza as constantes da classe - ex: SwingConstants.RIGHT
	 */
	public void setColumnAlign (Integer aligns[])
	{
		if (aligns == null)
			return;
		
		if (this.getColumnCount() > 0)
		{
			for (int i=0; i < this.getColumnCount(); i++)
			{	
				if (i<aligns.length && aligns[i]!=null){
					DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer();
					dtcr.setHorizontalAlignment(aligns[i].intValue());
					this.getColumnModel().getColumn(i).setCellRenderer(dtcr);
				}								
			}
		}
	}
	
	/**
	 * Metodo respons�vel pelo controle dos objetos selecionados na tabela.
	 * 
	 * @return 
	 * 		<BR>Object    - Se apenas uma linha estiver selecionada. Ex: Aluno, Curso...
	 * 		<BR>ArrayList - Se mais de uma linha estiver selecionada.
	 */
	public ArrayList getSelectedItens(){
		
		if (this.getModel() instanceof TableModelBase){
			
			TableModelBase model = (TableModelBase) this.getModel();
			
			if (this.getSelectedRows().length > 0 && model.getDados().size()>0){
				
				ArrayList objetos = new ArrayList();
				int[] rows = this.getSelectedRows();
				for (int i = 0; i < rows.length; i++) {
					
					int index = rows[i];
					if (index < model.getDados().size()){
						objetos.add(model.getDados().get(index));
					}					
				}
				
				return objetos;
			}
		}
		
		return new ArrayList();		
		
	}
	
	/**
	 * Metodo respons�vel pelo controle de um determinado objeto selecionado na tabela.
	 * 
	 * @return 
	 * 		<BR>Object    - Retorna o objeto selecionado.
	 */
	public Object getOnlySelectedItem(){
		
		if (this.getModel() instanceof TableModelBase){
			
			TableModelBase model = (TableModelBase) this.getModel();
			
			if (this.getSelectedRow()>=0 && model.getDados()!=null && model.getDados().size()>0
					&& this.getSelectedRow()<model.getDados().size()){
				
				return model.getDados().get(this.getSelectedRow());
			}
		}
		
		return null;		
		
	}
	
	public void clear(){
		
		if (this.getModel()!=null && this.getModel() instanceof TableModelBase){
			((TableModelBase)this.getModel()).getDados().clear();
			this.updateUI();
		}
	}
	
	public void setDados(ArrayList dados){
		
		if (this.getModel()!=null && this.getModel() instanceof TableModelBase){
			this.clear();
			((TableModelBase)this.getModel()).getDados().addAll(dados);
			this.updateUI();
		}
	}
	
	public ArrayList getDados(){
		
		if (this.getModel()!=null && this.getModel() instanceof TableModelBase){
			
			return ((TableModelBase)this.getModel()).getDados();
		}
		return null;
	}
	
	public void addObjeto(Object obj){
		if(obj!=null){
			this.getDados().add(obj);
			this.updateUI();
		}
	}
	
	public void setParametros(Integer sizes[], Integer aligns[], boolean addHeaderListener){
		
		this.setColumnSize(sizes);
		this.setColumnAlign(aligns);
		
		if (addHeaderListener && getModel() instanceof TableModelBase)
			this.getTableHeader().addMouseListener(new HeaderListener (this.getTableHeader(), (TableModelBase) getModel()));
	}
	
	public void removeSelectedItens(){
		
		if(this.getSelectedItens().size()>0){
			this.getDados().removeAll(this.getSelectedItens());
			this.updateUI();
		}
	}

	public TableModelBase getModelBase() {
		return model;
	}

	public void setModelBase(TableModelBase model) {
		this.model = model;
	}
	
	/**
	 * Este metodo adiciona acao ao selecionar um item da tabela
	 * e chama o metodo onChangeSelection(), que deve ser sobrescrito ao 
	 * instanciar o classe TableBase();
	 * Ex: 
	 * 		TableBase table = new TableBase(){
	 * 			
	 * 			onChangeSelection(){
	 * 			}
	 * 		}
	 * 		table.addItemChangeSelection(true);
	 */
	public void addItemChangeSelection(boolean change){
		
		if(change){
			
			this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	        ListSelectionModel rowSM = this.getSelectionModel();
	        rowSM.addListSelectionListener(new ListSelectionListener() {

	            public void valueChanged(ListSelectionEvent e) {
	                if (e.getValueIsAdjusting()) return;
	                	onChangeSelection(); 
	            }
	        });
		}
	}
	
	/**
	 * Metodo executado ao alterar o item selecionado na tabela.
	 */
	public void onChangeSelection(){}
	
	
	/**
	 * Este metodo adiciona acao ao selecionar um item da tabela
	 * e chama o metodo definido na Interface IChangeSelection
	 * 
	 */
	public void addItemChangeSelection(final IChangeSelection change){
		
		if(change!=null){
			
			this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	        ListSelectionModel rowSM = this.getSelectionModel();
	        rowSM.addListSelectionListener(new ListSelectionListener() {

	            public void valueChanged(ListSelectionEvent e) {
	                if (e.getValueIsAdjusting()) return;
	                	change.onChangeSelection(); 
	            }
	        });
		}
	}
	
	/**
	 * Este metodo adiciona acao ao clicar em um item da tabela
	 * e chama o metodo definido na Interface IChangeSelection
	 * 
	 */
	public void addMouse1Click(final IChangeSelection change){
		
		if(change!=null){
			
			this.addMouseListener(new MouseAdapter(){
				public void mouseClicked(MouseEvent e) {
					super.mouseClicked(e);
					change.onChangeSelection();
				}
			});
		}
	}
	
	/**
	 * Este metodo adiciona acao ao clicar 2 vezes em um item da tabela
	 * e chama o metodo definido na Interface IChangeSelection
	 * 
	 */
	public void addMouse2Click(final IChangeSelection change){
		
		if(change!=null){
			
			this.addMouseListener(new MouseAdapter(){
				public void mouseClicked(MouseEvent e) {
					super.mouseClicked(e);
					if(e.getClickCount()>1)
						change.onChangeSelection();
				}
			});
		}
	}
	
	
	/**
	 * Este metodo faz com que a tela enter funcione como a tecla TAB na tabela
	 * percorrendo somente os campo editaveis.
	 */
	public static void controlEnterTable(JTable tb) {
		InputMap im = tb.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
		KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
		KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
		im.put(enter, im.get(tab));
		final Action oldTabAction = tb.getActionMap().get(im.get(tab));
		final Action tabAction = new AbstractAction() {

			public void actionPerformed(ActionEvent e) {
				JTable table = (JTable) e.getSource();
				int row = table.getSelectedRow();
				int originalRow = row;
				int column = table.getSelectedColumn();
				int originalColumn = column;

				if ((row + 1 == table.getRowCount()) && (column + 1 == table.getColumnCount())) {
					oldTabAction.actionPerformed(e);
					table.changeSelection(row + 1, 0, false, false);
					return;
				}

				if(column+1 < table.getColumnCount()){
					if (!table.isCellEditable(row, column+1)){
						column = column+1;
					}
				}

				oldTabAction.actionPerformed(e);
				while (!table.isCellEditable(row, column)) {
					oldTabAction.actionPerformed(e);
					row = table.getSelectedRow();
					column = table.getSelectedColumn();
					if (row == originalRow && column == originalColumn) {
						break;
					}
				}

				table.editCellAt(table.getSelectedRow(), table.getSelectedColumn());
				if(table.getCellEditor()!=null){
					Component c = table.getCellEditor().getTableCellEditorComponent(table, 
							table.getValueAt(table.getSelectedRow(), table.getSelectedColumn()), 
							true, table.getSelectedRow(), table.getSelectedColumn());
					if(c!=null)
						c.requestFocus();
				}


			}
		};
		tb.getActionMap().put(im.get(tab), tabAction);
	}
	
	/**
	 * Adiciona o SimpleCellEditor na tabela.
	 */
	public static void addSimpleCellEditor(TableBase table){
		table.setDefaultEditor(Object.class, new SimpleCellEditor(table, new JTextField()));
	}
	
	
	public void setDinamicRowHeight(int column){
		TableColumn tc = getColumnModel().getColumn(column);
		if(tc!=null){
			tc.setCellRenderer(new ColumnRenderer(){
				public java.awt.Component getTableCellRendererComponent(
						JTable table, Object value, boolean isSelected,
						boolean hasFocus, int row, int column) {
					
					String valor = (String) value;
					
					if(valor==null){
						valor =  "";
					}
					
					JTextArea jta = new JTextArea();
					jta.setLineWrap(true);
					
					jta.setText(valor);
					
					jta.setBackground(table.getBackground());
					jta.setForeground(table.getForeground());
					if(isSelected){
						jta.setBackground(table.getSelectionBackground());
						jta.setForeground(table.getSelectionForeground());
					}
					
					table.setRowHeight(row, jta.getPreferredSize().height);
					
					return jta;
				}
			});
		}
	}
	
	public void setRendererPadrao(ColumnRenderer renderer){
		this.setDefaultRenderer(Object.class, renderer);
		this.setDefaultRenderer(String.class, renderer);
		this.setDefaultRenderer(Double.class, renderer);
		this.setDefaultRenderer(Integer.class, renderer);
		this.setDefaultRenderer(Date.class, renderer);
		this.setDefaultRenderer(Boolean.class, this.getDefaultRenderer(Boolean.class));
				
		/*@requisicao [2389]*/
		if (this.getColumnCount() > 0)
		{
			
			for (int i=0; i < this.getColumnCount(); i++)
			{
				this.getColumn(this.getColumnName(i)).setCellRenderer(renderer);
			}
		}

	}
	

}
